package permission

import (
	"context"

	v1 "gitee.com/liangziyisheng/caas-platform-mc/api/permission/v1"
	"gitee.com/liangziyisheng/caas-platform-mc/internal/consts"
	"gitee.com/liangziyisheng/caas-platform-mc/internal/dao"
	"gitee.com/liangziyisheng/caas-platform-mc/internal/model/entity"
	"gitee.com/liangziyisheng/caas-platform-mc/internal/service"
	"gitee.com/liangziyisheng/caas-platform-mc/utility/authorization"
	"gitee.com/liangziyisheng/caas-platform-mc/utility/cache"

	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/glog"
)

type sPermission struct{}

var l = g.Log("logger for Permission")

func New() *sPermission {
	return &sPermission{}
}

func init() {
	l.SetFlags(glog.F_FILE_LONG)
	service.RegisterPermission(New())
}

func (s *sPermission) List(ctx context.Context, in *v1.ListInput) (out *v1.ListOutput, err error) {
	l.Info(ctx, "permission list")
	out = &v1.ListOutput{}
	err = dao.Permission.Ctx(ctx).Where(dao.Permission.Columns().MenuId, in.MenuId).ScanAndCount(&out.Data, &out.Total, true)
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.ListPermissionFailed, in))
	}
	return out, nil
}
func (s *sPermission) Info(ctx context.Context, in *v1.InfoInput) (out *v1.InfoOutput, err error) {
	return nil, nil
}

func (s *sPermission) Add(ctx context.Context, in *v1.AddInput) (out *v1.AddOutput, err error) {
	l.Info(ctx, "permission add")
	id, err := dao.Permission.Ctx(ctx).Data(in.Permission).InsertAndGetId()
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.AddPermissionFailed, in.Permission))
	}
	out = &v1.AddOutput{Id: id}
	// 设置缓存
	err = cache.InitCache(ctx, consts.InitialCacheKeys.PermissionsKey, true)
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(consts.ResetPermissionCacheFailed)
	}
	return out, nil
}

func (s *sPermission) Update(ctx context.Context, in *v1.UpdateInput) (out *v1.UpdateOutput, err error) {
	out = &v1.UpdateOutput{}
	// 查询permission的详情
	p := entity.Permission{}
	err = dao.Permission.Ctx(ctx).Where(dao.Permission.Columns().Id, in.Id).Scan(&p)
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.PermissionNotExist, in.Id))
	}
	if p.Id == 0 {
		return nil, gerror.NewCode(consts.PermissionNotExist)
	}
	// 检查permission是否在role中使用,如果使用则提示不能修改
	e := authorization.NewEnforcer()
	usedList, err := e.GetFilteredPolicy(1, p.Path, p.Operation)
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(consts.QueryPolicyFailed)
	}
	if len(usedList) > 0 {
		return nil, gerror.NewCode(consts.PermissionAssignedByRole)
	}

	out.Rows, err = dao.Permission.Ctx(ctx).Data(in.Permission).Where(dao.Permission.Columns().Id, in.Id).UpdateAndGetAffected()
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.UpdatePermissionFailed, in.Permission))
	}
	if out.Rows == 0 {
		return nil, gerror.NewCode(gcode.WithCode(consts.UpdateFailed, in.Id))
	}
	// 设置缓存
	err = cache.InitCache(ctx, consts.InitialCacheKeys.PermissionsKey, true)
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(consts.ResetPermissionCacheFailed)
	}
	return out, nil
}

func (s *sPermission) Delete(ctx context.Context, in *v1.DeleteInput) (out *v1.DeleteOutput, err error) {
	// 先查询permission的详情
	p := entity.Permission{}
	err = dao.Permission.Ctx(ctx).Where(dao.Permission.Columns().Id, in.Id).Scan(&p)
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.PermissionNotExist, in.Id))
	}
	if p.Id == 0 {
		return nil, gerror.NewCode(consts.PermissionNotExist)
	}
	// 再检查permission是否仍在role中使用,如果在使用则提示不能删除
	e := authorization.NewEnforcer()
	usedList, err := e.GetFilteredPolicy(1, p.Path, p.Operation)
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(consts.QueryPolicyFailed)
	}
	if len(usedList) > 0 {
		return nil, gerror.NewCode(consts.PermissionAssignedByRole)
	}

	// 最后才删除
	rs, err := dao.Permission.Ctx(ctx).Where(dao.Permission.Columns().Id, in.Id).Delete()
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.DeletePermissionFailed, in.Id))
	}
	out = &v1.DeleteOutput{}
	if out.Rows, err = rs.RowsAffected(); err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(gcode.WithCode(consts.DeletePermissionFailed, in.Id))
	}
	if out.Rows == 0 {
		return nil, gerror.NewCode(gcode.WithCode(consts.DeleteFailed, in.Id))
	}
	// 设置缓存
	err = cache.InitCache(ctx, consts.InitialCacheKeys.PermissionsKey, true)
	if err != nil {
		l.Error(ctx, err)
		return nil, gerror.NewCode(consts.ResetPermissionCacheFailed)
	}
	return out, nil
}
